package com.linQing.waterWork.controller;

import com.linQing.waterWork.annotation.RepeatSubmitLimit;
import com.linQing.waterWork.exception.ServiceCode;
import com.linQing.waterWork.exception.ServiceException;
import com.linQing.waterWork.mapper.sql.SwsDatainfoMapper;
import com.linQing.waterWork.modle.dto.CurveRequest;
import com.linQing.waterWork.modle.dto.ReportRequest;
import com.linQing.waterWork.modle.vo.AnalogVo;
import com.linQing.waterWork.service.mongodb.ReportService;
import com.linQing.waterWork.web.JsonResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @version 1.0.0
 * @program: linqing
 * @description: TODO 报表管理页面相关接口
 * @author: lsk
 * @create: 2024-04-16 10:45
 * @since jdk1.8
 **/
@Api(value = "report", tags = "报表管理页面相关接口")
@RestController
@RequestMapping("/report")
public class ReportController {

    @Resource
    private ReportService reportService;

    @Resource
    private SwsDatainfoMapper swsDatainfoMapper;

    @Resource
    private CacheManager cacheManager;

    @ApiOperation("曲线分析接口")
    @PostMapping("/getCurve")
//    @RepeatSubmitLimit(businessKey = "pageAll", businessParam = "#pageAll", time = 2)
    public JsonResult<?> getCurve (@RequestBody CurveRequest request) {

        if (request.getEquipmentID() == null) {
            throw new ServiceException(ServiceCode.PARAMS_ERROR, "请传入设备ID");
        }
        //判断开始时间为空,则将当前时间的前一个小时赋值给开始时间
        if (request.getStartTime() == null) {
            request.setStartTime(new Date(System.currentTimeMillis() - 10800000));
        }
        //判断结束时间为空,则将当前时间赋值给结束时间
        if (request.getEndTime() == null) {
            request.setEndTime(new Date());
        }
        //判断开始时间大于结束时间则抛出异常
        if (request.getStartTime() != null && request.getEndTime() != null && request.getStartTime().compareTo(request.getEndTime()) > 0) {
            throw new ServiceException(ServiceCode.TIME_PARAMS_ERROR, "时间日期处于不允许的区间");
        }
        //判断开始时间与结束时间不在同一个年份则抛出异常
        if (request.getStartTime() != null && request.getEndTime() != null && request.getStartTime().getYear() != request.getEndTime().getYear()) {
            throw new ServiceException(ServiceCode.TIME_PARAMS_ERROR, "开始时间与结束时间不在同一个年份");
        }
        //判断时间间隔为空,则将时间间隔设置为10分钟
//        if (request.getPeriodTime() == null) {
//            request.setPeriodTime(10);
//        }
//        //判断时间间隔小于等于0,则抛出异常
//        if (request.getPeriodTime() <= 0) {
//            throw new ServiceException(ServiceCode.PARAMS_ERROR, "时间间隔不合法");
//        }
        return JsonResult.ok(reportService.getCurve(request));
    }

    //    @RepeatSubmitLimit注解的businessKey属性设置为"pageAll"，businessParam属性设置为"#pageAll"，time属性设置为2，这意味着该方法每2秒只能被调用一次
    @ApiOperation("分页查询报表信息接口")
    @PostMapping("/pageAll")
//    @RepeatSubmitLimit(businessKey = "pageAll", businessParam = "#pageAll", time = 2)
    public JsonResult<?> pageAll(@RequestBody ReportRequest request) {

        //判断pageNum,pageSize参数为空则设置默认值
        request.setPageNum(request.getPageNum() == null ? 1 : request.getPageNum());
        request.setPageSize(request.getPageSize() == null ? 10 : request.getPageSize());
        //判断pageNum,pageSize小于等于0则抛出异常
        if (request.getPageNum() <= 0 || request.getPageSize() <= 0) {
            throw new ServiceException(ServiceCode.PARAMS_ERROR, "pageNum,pageSize参数不合法");
        }
        if (request.getEquipmentID() == null) {
            throw new ServiceException(ServiceCode.PARAMS_ERROR, "请传入设备ID");
        }
        //判断开始时间,结束时间为空则抛出异常
        if (request.getStartTime() == null && request.getEndTime() == null) {
            throw new ServiceException(ServiceCode.TIME_PARAMS_ERROR, "时间不可为空");
        }
        //判断开始时间大于结束时间则抛出异常
        if (request.getStartTime() != null && request.getEndTime() != null && request.getStartTime().compareTo(request.getEndTime()) > 0) {
            throw new ServiceException(ServiceCode.TIME_PARAMS_ERROR, "时间日期处于不允许的区间");
        }
        //判断开始时间与结束时间不在同一个年份则抛出异常
        if (request.getStartTime() != null && request.getEndTime() != null && request.getStartTime().getYear() != request.getEndTime().getYear()) {
            throw new ServiceException(ServiceCode.TIME_PARAMS_ERROR, "开始时间与结束时间不在同一个年份");
        }

        return JsonResult.ok(reportService.getAggregatedData(request));
    }
    @ApiOperation("查询实时信息接口")
    @GetMapping("/getData")
//    @RepeatSubmitLimit(businessKey = "pageAll", businessParam = "#pageAll", time = 2)
    public JsonResult<?> getData(String equipmentID) {

        if (equipmentID == null) {
            throw new ServiceException(ServiceCode.PARAMS_ERROR, "请传入设备ID");
        }
        return JsonResult.ok(reportService.getDigital(equipmentID));
    }

    @ApiOperation("导出报表信息")
    @PostMapping("/export")
    @RepeatSubmitLimit(businessKey = "pageAllToInfo", businessParam = "#pageAllToInfo", time = 10)
    public void export(@RequestBody ReportRequest request, HttpServletResponse response) throws IOException {
        //判断type参数为空或不等于0,1,2则抛出异常
        if (request.getEquipmentID() == null) {
            throw new ServiceException(ServiceCode.PARAMS_ERROR, "请传入设备ID");
        }
        //判断开始时间,结束时间为空则抛出异常
        if (request.getStartTime() == null && request.getEndTime() == null) {
            throw new ServiceException(ServiceCode.TIME_PARAMS_ERROR, "时间不可为空");
        }
        //判断开始时间大于结束时间则抛出异常
        if (request.getStartTime() != null && request.getEndTime() != null && request.getStartTime().compareTo(request.getEndTime()) > 0) {
            throw new ServiceException(ServiceCode.TIME_PARAMS_ERROR, "时间日期处于不允许的区间");
        }
        //判断开始时间与结束时间不在同一个年份则抛出异常
        if (request.getStartTime() != null && request.getEndTime() != null && request.getStartTime().getYear() != request.getEndTime().getYear()) {
            throw new ServiceException(ServiceCode.TIME_PARAMS_ERROR, "开始时间与结束时间不在同一个年份");
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("报表信息", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        request.setPageNum(1);
        request.setPageSize(Integer.MAX_VALUE);
        List<AnalogVo> report = reportService.getReport(request);
        // 创建工作簿和工作表
        XSSFWorkbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");
        // 创建标题行并设置样式
        Row titleRow = sheet.createRow(0);

        titleRow.createCell(0).setCellValue("更新时间");

        // 假设swsDatainfoMapper是一个已经注入的bean
        // 通过映射器获取汉字并设置Excel列标题
        Map<Integer, String> numberToChineseMap = report.stream()
                .flatMap(analogVo -> analogVo.getAnalogValues().keySet().stream().map(Integer::parseInt))
                .distinct()
                .collect(Collectors.toMap(
                        Function.identity(),
                        this::getChineseByNumber,
                        (existing, replacement) -> existing
                ));
//        创建逆向yinsghe
        Map<String, Integer> chineseToNumberMap = new HashMap<>();
        for (Map.Entry<Integer, String> entry : numberToChineseMap.entrySet()) {
            chineseToNumberMap.put(entry.getValue(), entry.getKey());
        }
        // 添加AnalogValues的列标题
        int cellIndex = 1;
        for (String chineseName : numberToChineseMap.values()) {
            titleRow.createCell(cellIndex++).setCellValue(chineseName);
        }

// 创建CellStyle对象，并设置字体加粗和居中对齐
        XSSFCellStyle style = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setBold(true);  // 设置字体加粗
        font.setFontHeightInPoints((short) 12);  // 可以设置字体大小
        style.setFont(font);
        style.setAlignment(HorizontalAlignment.CENTER);  // 设置水平居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);  // 设置垂直居中
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        // 应用CellStyle到标题行的所有单元格
        for (Cell cell : titleRow) {
            cell.setCellStyle(style);
        }

        List<String> headerKeys = new ArrayList<>(numberToChineseMap.values());

        // 写入数据行
        int rowNum = 1;
        for (AnalogVo analogVo : report) {
            // 在写入AnalogValues时，使用转换后的键来索引
            Row row = sheet.createRow(rowNum++);
            Cell cell = row.createCell(0);

            Date updateTime = analogVo.getUpdateTime();
            // 创建Calendar对象并设置时区为GMT+8
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeZone(TimeZone.getTimeZone("GMT+8"));

            // 将当前时间设置为Calendar对象的时间
            calendar.setTime(updateTime);

            // 减去8小时
            calendar.add(Calendar.HOUR_OF_DAY, -8);

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//            cell.setCellValue(dateFormat.format(calendar.getTime()));
            cell.setCellValue(dateFormat.format(updateTime));

            // 写入AnalogValues
            Map<String, Double> analogValues = analogVo.getAnalogValues();
            cellIndex = 1;
            for (String chineseName : headerKeys) {
                // 找到汉字对应的数字键
                Integer numberKey = chineseToNumberMap.get(chineseName);
                if (numberKey != null && analogValues.containsKey(numberKey.toString())) {
                    Double value = analogValues.get(numberKey.toString());
                    cell = row.createCell(cellIndex++);
                    cell.setCellValue(value);
                } else {
                    // 如果键不存在，写入默认值0.0
                    cell = row.createCell(cellIndex++);
                    cell.setCellValue(0.0);
                }
            }
        }
        XSSFCellStyle otherRowStyle = workbook.createCellStyle();
        XSSFFont otherRowFont = workbook.createFont();
        otherRowFont.setFontHeightInPoints((short) 12); // 可以设置字体大小
        otherRowStyle.setFont(otherRowFont);
        otherRowStyle.setAlignment(HorizontalAlignment.CENTER); // 设置水平居中
        otherRowStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 设置垂直居中
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                for (Cell cell : row) {
                    cell.setCellStyle(otherRowStyle);
                }
            }
        }
        for (int i = 0; i < headerKeys.size()+1; i++) {
//            sheet.autoSizeColumn(i, true); // 设置自适应宽度
            sheet.setColumnWidth(i, 24 * 256);
        }
//        sheet.autoSizeColumn(0, true);
        try (OutputStream out = response.getOutputStream()) {
            workbook.write(out);
        }
        workbook.close();
    }
    @Cacheable(value = "chineseNumberCache", key = "#number")
    public String getChineseByNumber(int number) {
        // 委托给mapper方法获取对应的汉字
        Cache cache = cacheManager.getCache("chineseNumberCache");
        Map<Integer, String> numberToChineseMap = null;
        if (cache != null) {
            numberToChineseMap = cache.get("numberToChineseMap", Map.class);
        }

        System.out.println();
        if (numberToChineseMap != null && numberToChineseMap.containsKey(number)) {
            return numberToChineseMap.get(number);
        } else {
            // 如果缓存中不存在，则从数据库查询
            return swsDatainfoMapper.selectDataInfoByDateId(number);
        }
    }


}

